# -*- coding:utf-8 -*-
# @FileName :corrector.py
# @Date: 2024/7/31
# @Author:天空之城
# 地址纠错模块

import json
import re
from difflib import get_close_matches
from address_normalizer.app.config import CHINA_REGIONS_JSON
import Levenshtein


class CorrectAddress:
    def __init__(self):
        self.file_path = CHINA_REGIONS_JSON
        self.locations = self.load_location_data()
        self.location_list = self.create_location_list()

    def load_location_data(self):
        with open(self.file_path, 'r', encoding='utf-8') as f:
            return json.load(f)

    def create_location_list(self):
        location_list = []
        for province, cities in self.locations.items():
            for city, districts in cities.items():
                # location_list.append(province + city)
                for district in districts:
                    location_list.append(province + city + district)
        return location_list

    def process(self, address, predicted_result):
        refinedAddress = self.correct_location(address)

    def correct_location(self, input_name):
        input_name = input_name[:9]  # 只选取前9个
        matches = get_close_matches(input_name, self.location_list, n=3, cutoff=0.5)
        if matches:
            return matches[0]
        else:
            return input_name

    def extract_other_address(self, address, result: dict, address_tuple: tuple = None):
        """
        province, city, district 分别代表address_tuple的三个元素
        """
        if address_tuple is None:
            province = city = district = ''
        else:
            province, city, district = address_tuple
        # 以省市区进行匹配
        for label, entity in result.items():
            if label == "province" and province in address:
                address = address.replace(province, '', 1)
            elif label == "city" and city in address:
                address = address.replace(city, '', 1)
            elif label == "district" and district in address:
                address = address.replace(district, '', 1)
            else:
                # 如果元组中的元素不存在，则用 entity 进行替换
                address = self.replace_incorrect_address(address, entity)
                address = address.replace(entity, '', 1)  # 只去除最前面的那个匹配项
        return address

    def map_address(self, address, result: dict):
        mapping = {i: {'char': char, 'mapped_value': None} for i, char in enumerate(address)}

        # 找到 district 的位置
        district_start = None
        if result.get('district'):
            district_pattern = re.escape(result['district'])
            match = re.search(district_pattern, address)
            if match:
                district_start = match.end()  # district 结束的地方

        for key, value in result.items():
            if value and key != 'district':  # 除了 district 以外的参数
                pattern = re.escape(value)  # 转义字符串以用于正则表达式
                matches = list(re.finditer(pattern, address))

                for match in matches:
                    if district_start is None or match.start() >= district_start:
                        # 仅在 district 之后保留字符的映射
                        for i in range(match.start(), match.end()):
                            mapping[i]['mapped_value'] = value  # 映射到参数值

        # 对于 district 后的字符，不丢弃映射
        if district_start is not None:
            for i in range(district_start, len(address)):
                if mapping[i]['mapped_value'] is None:
                    mapping[i]['mapped_value'] = 'Retained'

        return mapping

    @staticmethod
    def replace_incorrect_address(address: str, correct: str) -> str:
        window_size = len(correct)
        max_similarity = -1
        best_match_index = -1
        for i in range(len(address) - window_size + 1):
            window = address[i:i + window_size]
            similarity = Levenshtein.ratio(window, correct)
            if similarity > max_similarity:
                max_similarity = similarity
                best_match_index = i
        if best_match_index != -1:
            address = address[:best_match_index] + correct + address[best_match_index + window_size:]
        return address
